package com.firefly.admin.monitor.service.impl;

import com.firefly.admin.common.constant.Constants;
import com.firefly.admin.common.enums.ResultCodeEnum;
import com.firefly.admin.common.vo.Result;
import com.firefly.admin.monitor.entity.FyMonitorJob;
import com.firefly.admin.monitor.service.CommonJobService;
import com.firefly.admin.monitor.service.FyMonitorJobService;
import com.firefly.admin.monitor.vo.JobExecuteResult;
import com.firefly.admin.monitor.vo.MonitorJobStatusUpdateVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;

@Service
@Slf4j
public class CommonJobServiceImpl implements CommonJobService {

    @Lazy
    @Autowired
    private FyMonitorJobService fyMonitorJobService;
    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;
    private final Map<Long, ScheduledFuture<?>> futureMap = new HashMap<>();


    /**
     * 开始定时任务
     *
     * @param monitorJob 定时任务信息
     * @return 操作结果
     */
    @Override
    public Result<FyMonitorJob> startJob(FyMonitorJob monitorJob) {
        log.info(">>>>>> 启动任务 {} 开始 >>>>>>", monitorJob.getJobName());
        ScheduledFuture<?> future = futureMap.get(monitorJob.getJobId());
        if (future != null) {
            return Result.getResult(ResultCodeEnum.MONITOR_JOB_RUNNING_ALREADY_RUNNING);
        }
        ScheduledFuture<?> scheduledFuture = threadPoolTaskScheduler.schedule(() -> runningJob(monitorJob), triggerContext -> new CronTrigger(monitorJob.getJobCron()).nextExecutionTime(triggerContext));
        futureMap.put(monitorJob.getJobId(), scheduledFuture);
        return Result.success("启动成功", monitorJob);
    }

    /**
     * 执行一次任务
     *
     * @param fyMonitorJob 定时任务信息
     * @return 操作结果
     */
    @Override
    public Result<JobExecuteResult> executeOnceJob(FyMonitorJob fyMonitorJob) {
        JobExecuteResult jobExecuteResult = runningJob(fyMonitorJob);
        MonitorJobStatusUpdateVo cronJobStatusUpdateVo = new MonitorJobStatusUpdateVo();
        cronJobStatusUpdateVo.setJobId(fyMonitorJob.getJobId());
        cronJobStatusUpdateVo.setJobStatus(Constants.JobStatus.STOP);
        fyMonitorJobService.updateStatus(cronJobStatusUpdateVo);
        return Result.success(jobExecuteResult);
    }

    /**
     * 停止定时任务
     *
     * @param monitorJob 定时任务信息
     */
    @Override
    public void stopJob(FyMonitorJob monitorJob) {
        log.info(">>>>>> 停止任务 {} 开始 >>>>>>", monitorJob.getJobName());
        ScheduledFuture<?> future = futureMap.get(monitorJob.getJobId());
        if (future != null) {
            future.cancel(true);
            futureMap.remove(monitorJob.getJobId());
        }
    }

    private JobExecuteResult runningJob(FyMonitorJob monitorJob) {
        JobExecuteResult result;
        try {
            Class<?> jobClass = Class.forName(monitorJob.getJobClass());
            Object instance = jobClass.newInstance();
            Method method = jobClass.getMethod(monitorJob.getJobMethodName(), FyMonitorJob.class);
            result = (JobExecuteResult) method.invoke(instance, new Object[]{monitorJob});
            fyMonitorJobService.updateLastExecuteResult(monitorJob.getJobId(), result.getExecuteResult());
            log.info("############# start run job [{}]!!!!!!!!!!!", monitorJob.getJobName());
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
            result = new JobExecuteResult();
            result.setExecuteResult(Constants.LastExecuteResult.FAIL);
            result.setErrorMsg(e.getMessage());
        }
        return result;
    }
}
